package com.ncmmall.application.business.live.tencentcloud.im;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.codec.digest.HmacUtils;
import org.apache.commons.lang.math.RandomUtils;
import org.apache.http.client.fluent.Request;
import org.apache.http.entity.StringEntity;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.zip.Deflater;

/**
 * IM工具类
 */
@Slf4j
public class IMUtils {

    private static final String SDK_AppID = "1400428202";
    private static final String KEY = "b97793b416bed12b51ccbe1c19a70c28db9f347188b80e15c822af98460ad685";

    /**
     * 管理员用户名
     */
    public static final String ADMIN_ACCOUNT = "admin";

    /**
     * 凭证过期时间，默认2天有效
     */
    private static final int SIGN_EXPIRE_TIME = 86400 * 2;

    /**
     * 生成IM用户凭证
     *
     * @param userId 用户名
     * @return 凭证
     */
    public static String generateUserSign(String userId) {
        JSONObject sigDoc = new JSONObject();
        sigDoc.put("TLS.ver", "2.0");
        sigDoc.put("TLS.identifier", userId);
        sigDoc.put("TLS.sdkappid", SDK_AppID);
        sigDoc.put("TLS.expire", SIGN_EXPIRE_TIME);

        long currTime = System.currentTimeMillis() / 1000;
        sigDoc.put("TLS.time", currTime);
        sigDoc.put("TLS.sig", hmacsha256(userId, currTime));

        Deflater compressor = new Deflater();
        compressor.setInput(sigDoc.toString().getBytes(StandardCharsets.UTF_8));
        compressor.finish();

        byte[] compressedBytes = new byte[2048];
        int len = compressor.deflate(compressedBytes);
        compressor.end();
        return Base64.getEncoder().encodeToString(Arrays.copyOfRange(compressedBytes, 0, len));
    }

    private static String hmacsha256(String identifier, long currTime) {
        String content = "TLS.identifier:" + identifier + "\n"
                + "TLS.sdkappid:" + SDK_AppID + "\n"
                + "TLS.time:" + currTime + "\n"
                + "TLS.expire:" + SIGN_EXPIRE_TIME + "\n";
        byte[] bytes = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, KEY.getBytes(StandardCharsets.UTF_8))
                .hmac(content.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(bytes);
    }

    /**
     * 服务端请求rest接口地址，只能有管理员账号发起
     *
     * @param service 服务名称
     */
    private static String generateUrl(String service) {
        return "https://console.tim.qq.com/v4/" + service + "?sdkappid=" + SDK_AppID + "&identifier=" + ADMIN_ACCOUNT
                + "&usersig=" + generateUserSign(ADMIN_ACCOUNT) + "&random=" + RandomUtils.nextInt() + "&contenttype=json";
    }

    private static boolean isSuccess(JSONObject json) {
        return json.getString("ActionStatus").equals("OK");
    }

    /**
     * 创建直播群组
     *
     * @return 群id
     */
    public static String createGroup(String groupName) {

        JSONObject req = new JSONObject();
        req.put("Type", "AVChatRoom");
        req.put("Name", groupName);

        try {
            String body = Request.Post(generateUrl("group_open_http_svc/create_group"))
                    .body(new StringEntity(req.toString(), "utf-8"))
                    .execute()
                    .returnContent()
                    .asString(StandardCharsets.UTF_8);
            JSONObject json = JSON.parseObject(body);
            if (isSuccess(json)) {
                return json.getString("GroupId");
            }
            error("创建直播群组异常", req, body);
            throw new IllegalArgumentException(json.getString("ErrorInfo"));
        } catch (IOException e) {
            log.error("[请求IM网络异常]", e);
            throw new IllegalArgumentException("请求IM异常");
        }
    }

    /**
     * 解散直播群组
     *
     * @param groupId 群组id
     */
    public static void destroyGroup(String groupId) {

        JSONObject req = new JSONObject();
        req.put("GroupId", groupId);

        try {
            String body = Request.Post(generateUrl("group_open_http_svc/destroy_group"))
                    .body(new StringEntity(req.toString(), "utf-8"))
                    .execute()
                    .returnContent()
                    .asString(StandardCharsets.UTF_8);
            JSONObject json = JSON.parseObject(body);
            if (isSuccess(json)) {
                return;
            }
            error("解散群组异常", req, body);
            throw new IllegalArgumentException(json.getString("ErrorInfo"));
        } catch (IOException e) {
            log.error("[请求IM网络异常]", e);
            throw new IllegalArgumentException("请求IM异常");
        }
    }

    /**
     * 禁言24小时
     *
     * @param groupId  群组id
     * @param accounts 账号列表
     */
    public static void forbidSendMsg(String groupId, String... accounts) {
        forbidSendMsg0(groupId, false, accounts);
    }

    /**
     * 禁言
     *
     * @param groupId  群组id
     * @param cancel   是否取消禁言 true 取消 false 禁言
     * @param accounts 账号列表
     */
    private static void forbidSendMsg0(String groupId, boolean cancel, String... accounts) {

        JSONObject req = new JSONObject();
        req.put("GroupId", groupId);
        req.put("ShutUpTime", cancel ? 0 : 3600 * 24);
        req.put("Members_Account", new JSONArray(Arrays.asList(accounts)));

        try {
            String body = Request.Post(generateUrl("group_open_http_svc/forbid_send_msg"))
                    .body(new StringEntity(req.toString(), "utf-8"))
                    .execute()
                    .returnContent()
                    .asString(StandardCharsets.UTF_8);
            JSONObject json = JSON.parseObject(body);
            if (isSuccess(json)) {
                return;
            }
            error("禁言异常", req, body);
            throw new IllegalArgumentException(json.getString("ErrorInfo"));
        } catch (IOException e) {
            log.error("[请求IM网络异常]", e);
            throw new IllegalArgumentException("请求IM异常");
        }
    }

    /**
     * 取消禁言
     *
     * @param groupId  群组id
     * @param accounts 账号列表
     */
    public static void cancelForbidSendMsg(String groupId, String... accounts) {
        forbidSendMsg0(groupId, true, accounts);
    }

    /**
     * 获取群组在线人数
     *
     * @param groupId 群组id
     * @return 在线人数
     */
    public static int getOnlineMemberNum(String groupId) {

        JSONObject req = new JSONObject();
        req.put("GroupId", groupId);

        try {
            String body = Request.Post(generateUrl("group_open_http_svc/get_online_member_num"))
                    .body(new StringEntity(req.toString(), "utf-8"))
                    .execute()
                    .returnContent()
                    .asString(StandardCharsets.UTF_8);
            JSONObject json = JSON.parseObject(body);
            if (isSuccess(json)) {
                return json.getIntValue("OnlineMemberNum");
            }
            error("获取在线人数异常", req, body);
            throw new IllegalArgumentException(json.getString("ErrorInfo"));
        } catch (IOException e) {
            log.error("[请求IM网络异常]", e);
            throw new IllegalArgumentException("请求IM异常");
        }
    }

    /**
     * 请求异常日志
     *
     * @param message 异常消息
     * @param req     请求内容
     * @param body    响应内容
     */
    private static void error(String message, JSONObject req, String body) {
        log.error("{}:{}", message, req);
        log.error("{}:{}", message, body);
    }

}
